import pandas as pd
from sklearn.cluster import KMeans
from sklearn.preprocessing import StandardScaler
import matplotlib.pyplot as plt
import seaborn as sns
import warnings
warnings.filterwarnings('ignore')

class ClusterUtils(object):
    def __init__(self):
        # 读取CSV数据
        self.df = pd.read_csv('scenic_data.csv')
    
    def cluster(self, k):
        """
        执行KMeans聚类
        :param k: 聚类数量
        """
        # 提取特征并标准化
        features = self.df[['non_weekend_ratio', 'elderly_ratio', 'out_province_ratio']]
        scaler = StandardScaler()
        scaled_features = scaler.fit_transform(features)
        
        # 执行KMeans聚类
        kmeans = KMeans(n_clusters=k, random_state=42, n_init=10)
        self.df['cluster'] = kmeans.fit_predict(scaled_features)
        
        # 查看聚类结果
        print(self.df[['tourist_agency_name', 'cluster']])
        
        # 查看聚类中心（逆标准化，还原为原始特征尺度）
        centers = scaler.inverse_transform(kmeans.cluster_centers_)
        centers_df = pd.DataFrame(centers, columns=['non_weekend_ratio', 'elderly_ratio', 'out_province_ratio'])
        print(centers_df)
        self.df.to_csv('scenic_data_with_cluster.csv', index=False)  # 保存带聚类结果的CSV
        
        # 聚类中心可视化（长表格式转换与分组柱状图）
        center_df = pd.DataFrame(centers, columns=features.columns)
        center_df['cluster'] = [f'簇{i+1}' for i in range(centers.shape[0])]
        centers_long = center_df.melt(id_vars=['cluster'], var_name='metric', value_name='value')
        
        # 设置中文显示
        plt.rcParams['font.sans-serif'] = ['SimHei']
        plt.rcParams['axes.unicode_minus'] = False
        colors = ['#f47d84', '#fffbfe', '#2c2e02', '#a62278', '#96ad51']
        
        # 绘制分组柱状图
        plt.figure(figsize=(10, 6))
        g = sns.barplot(x='metric', y='value', hue='cluster', data=centers_long, palette=colors)
        plt.title('各聚类中心特征对比', fontsize=14)
        plt.xlabel('特征指标', fontsize=12)
        plt.ylabel('特征值', fontsize=12)
        plt.legend(title='簇', bbox_to_anchor=(-0.1, 1), loc='upper left')
        
        # 为柱状图添加数值标签
        for p in g.patches:
            height = p.get_height()
            g.text(p.get_x() + p.get_width()/2., height + 0.02, f'{height:.2f}', ha='center')
        plt.tight_layout()
        plt.show()

if __name__ == '__main__':
    cl = ClusterUtils()
    cl.cluster(k=3)  # 这里k的值可根据业务需求或轮廓系数法结果调整
